package com.cl.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.coobird.thumbnailator.Thumbnails;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.cl.dao.CommonDao;
import com.cl.dao.SearchDao;
import com.cl.entity.CcPay;
import com.cl.entity.CeAttachment;
import com.cl.entity.Image;
import com.cl.entity.Rel;
import com.cl.entity.UUser;
import com.cl.util.CommonUtil;
import com.cl.util.DateUtil;

@Service
public class FileService {

	final MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
    @Autowired
    private CommonDao commonDao;
    
    @Autowired
    private SearchDao searchDao;

    @Autowired
    private CommonUtil commonUtil;
    
    @Value("#{applicationProperties['path.dc.workpath.win']}")
    private String workpath_win;

    @Value("#{applicationProperties['path.dc.workpath.linux']}")
    private String workpath_linux;
    
    static private String path_work=null;
    static private String path_upload=null;
    
    @Value("#{applicationProperties['PAY_EXCEL_PATH']}")
	private String outPath;

    static final String CONTENT_TYPE = "text/html; charset=UTF-8";

    private static final String REQ_ENCODE = "utf-8";

    static SimpleDateFormat FMT_FPATH = new SimpleDateFormat("yyyy" + File.separator
            + "MM"
            + File.separator
            + "dd"
            + File.separator
            + "HHmmss_");

    static SimpleDateFormat FMT_FIMAGE = new SimpleDateFormat("yyyy.MM.dd");
    
    //用于导入影像excel时方便去重
    public static Set<String> imageSet = Collections.synchronizedSet(new HashSet<String>());
    
    @Value("#{applicationProperties['IMAGE_REWARD']}")
    private String imageReward;
    
    @Autowired
    private PayCaculateService payCaculateService;
       
    
    public  String getPathWork(){
    	if(path_work==null){
	    	if(File.separatorChar=='/')
	    		path_work= workpath_linux;
	    	else
	    		path_work= workpath_win;
			File dir = new File(path_work);
			if (!dir.exists() || !dir.isDirectory()) {
				dir.mkdirs();
			}
    	}
    	return path_work;
    }
    public  String getPathUpload(){
    	if(path_upload==null){
    		path_upload=getPathWork()+File.separator
    				+"upload"+File.separator;
			File dir = new File(path_upload);
			if (!dir.exists() || !dir.isDirectory()) {
				dir.mkdirs();
			}
    	}   
    	return path_upload;
    }
    public void onOpenFile(String fp, HttpServletRequest request, HttpServletResponse response) throws IOException {
        fp = fp.replace("/", File.separator);
        File fileIn = new File(getPathUpload() + fp);
        if(fp.indexOf("CC_Pay_Histroy_Excel")>-1){
        	Path payPath = Paths.get(getPathWork()+File.separator+outPath+File.separator).resolve(fp);
        	fileIn = new File(payPath.toString());
        }

        if (!fileIn.exists()) {
            response.sendRedirect("resources/images/no_image_available.jpg");
            return;
        }
        String s = request.getParameter("size");
        if (s != null) {
            int ds = Integer.parseInt(s);
            fileIn = getFnBySize(fileIn, ds);
        }
        String ftype = "";
        int ind = fp.lastIndexOf('.');
        if (ind != -1)
            ftype = fp.substring(ind).toLowerCase();
        response.setContentType(fileTypeMap.getContentType(fileIn));
        response.addHeader("Content-Disposition", "attachment;filename=" + fp);
        InputStream is = new FileInputStream(fileIn);
        OutputStream os = response.getOutputStream();//得到输出流
        byte data[] = new byte[4096];//缓冲字节数
        int size = is.read(data);
        while (size != -1) {
            os.write(data, 0, size);
            size = is.read(data);
        }
        is.close();
        os.flush();
        os.close();
    }
    /**
     * 抽点
     * @param fileIn
     * @param ds
     * @return
     * @throws IOException
     */
    static public File getFnBySize(File fileIn,int ds) throws IOException{
  	 if(fileIn==null || !fileIn.exists())
  		 return null;
  	 String fp = fileIn.getPath();
  	int pos = fp.lastIndexOf(".");
  	String suffix = fp.substring(pos+1).toLowerCase();
  	String fp1 = fp.substring(0,pos)+"_"+ds+"."+suffix;
  	File fileIn1 = new File(fp1);
  	//抽点文件不存在，抽之
  	if(!fileIn1.exists() && (suffix.equals("jpg")||suffix.equals("png"))){
  		Thumbnails.of(fileIn).size(ds, ds).outputFormat(suffix).toFile(fileIn1);
  	}
  	return fileIn1;	 
   }


    //清除本尊及抽点影像
    private void clearImgFiles(Image img){
    	String fnp = img.getCdlabel().replace(".", File.separator)
                + File.separator
                + img.getImgFile();
    	//.png getImgFile带后缀,  jpg getImgFile保存不带后缀
    	if(!fnp.endsWith(".png"))
    		fnp+=".jpg";
    	FileWrapper.clearFiles(getPathUpload() +fnp);
    	
    }
    private void clearAttach(CeAttachment ca){
    	FileWrapper.clearFiles(getPathUpload() +ca.getPath());
    }
    public void onFileUpload(MultipartFile[] files, HttpServletRequest request, HttpServletResponse response) throws IllegalStateException, IOException {
        String ip = commonUtil.getIpAddress(request);
        String userId = commonUtil.getCurrentUserID();
        UUser usr = commonUtil.getCurrentUser();
        String entity_to = request.getParameter("entity_to");
        String entity_rel = request.getParameter("entity_rel");
        String entity_id = request.getParameter("entity_id");
        response.setContentType(CONTENT_TYPE);
        PrintWriter out = response.getWriter();
        // 检查form是否有enctype="multipart/form-data"
        StringBuffer sbuf = null;
        ObjectMapper objectMapper = new ObjectMapper();
        //c4w 7.16 上传不一定关联，此方法是复用的，需要判断是否需要关联
        Integer maxOrd=null;
        if(entity_rel!=null)
        	maxOrd = searchDao.getMaxOrd(Long.parseLong(request.getParameter("entity_rel_to")), entity_rel, entity_to.toUpperCase());
        for (MultipartFile file : files) {
            if (file.isEmpty()) continue;
            Date ct = new Date();
            String ofn = file.getOriginalFilename();
            String fnp = FMT_FPATH.format(ct) + usr.getId() + "_" + ofn;
            if (entity_to != null && entity_to.equals("CeAttachment")) {
            	CeAttachment fe;
            	 if(entity_id==null){
            		 fe = new CeAttachment();
            	 }else{
            		 fe=(CeAttachment)searchDao.getEntity(CeAttachment.class, Long.parseLong(entity_id));
            		 clearAttach(fe);
            	 }
                fe.setName(ofn);
                fe.setFilesize(new BigDecimal(file.getSize()));
                fe.setPath(fnp);
                fe.setSuffix(FileWrapper.getFileExt(ofn));
                commonDao.saveDBOject(fe, fe.toString(), userId, "");
                //上传并关联
                if (entity_rel != null) {
                    Rel rel = new Rel();
                    rel.setId1(Long.parseLong(request.getParameter("entity_rel_to")));
                    rel.setEntity1(entity_rel);
                    rel.setId2(fe.getId());
                    rel.setEntity2(entity_to.toUpperCase());
                    if(maxOrd!=null)
                    	rel.setOrd(new BigDecimal(++maxOrd));
                    commonDao.saveDBOject(rel, objectMapper.writeValueAsString(rel), userId, ip);
                }
            } else if (entity_to != null && entity_to.equals("Image")) {
                Image fe;
                
                if(entity_id==null){
                	fe= new Image();
                    fe.setImageSource("外来影像");
                    fe.setUsage("个人");
                    commonDao.saveDBOject(fe);
                    
                    //上传并计算稿酬
                    CcPay pay = new CcPay("dao.hb.Image",fe.getPrimaryId(),new Date(),"djr");
                    //设置稿酬日志题名及当事人
                    pay.setAuthorId(fe.getPhotographer());
                    pay.setTitle(fe.getImageName());
                    
                    //稿费从配置文件中读取
        			pay.setReward(new BigDecimal(imageReward));
                    commonDao.savePay(fe, pay, userId, ip);
                }
                else{
                	fe=(Image)searchDao.getEntity(Image.class, Long.parseLong(entity_id));
                	//删除已存在的影像
                	clearImgFiles(fe);
                	

                }
                String cdlabel = "Y" + FMT_FIMAGE.format(ct);
                fe.setCdlabel(cdlabel);
                fe.setImageName(ofn);
                String fext = FileWrapper.getFileExt(ofn);
                if (fext.endsWith("jpg")) {
                    fe.setImgFile("img" + fe.getImageId());
                    fnp = cdlabel.replace(".", File.separator)
                            + File.separator
                            + fe.getImgFile()
                            + ".jpg";
                } else {
                    fe.setImgFile("img"
                            + fe.getImageId()
                            + "."
                            + fext);
                    fnp = cdlabel.replace(".", File.separator)
                            + File.separator
                            + fe.getImgFile();
                }
                fe.setPathMiddle(fnp);
                fe.setLastUpdate(ct);
                
            	//更新稿酬日志
            	commonDao.updatePays(fe, userId, ip);
                commonDao.saveDBOject(fe, objectMapper.writeValueAsString(fe), userId, ip);
                //TODO IMAGE表未记录文件后缀,目前均认为是jpg, 如果.jpg 则imgFile与老系统一致,不加后缀，否则imgFile带后缀


                //上传并关联
                if (entity_rel != null) {
                	Long relEntityId = Long.parseLong(request.getParameter("entity_rel_to"));

                    Rel rel = new Rel();
                    rel.setId1(relEntityId);
                    rel.setEntity1(entity_rel);
                    rel.setId2(fe.getImageId());
                    rel.setEntity2(entity_to.toUpperCase());
                    if(maxOrd!=null)
                    	rel.setOrd(new BigDecimal((++maxOrd)));
                    commonDao.saveDBOject(rel, objectMapper.writeValueAsString(rel), userId, ip);

                    //有关联实体则将稿酬也与实体进行关联
                    CcPay pay = searchDao.getRelPay("Image", fe.getImageId(), "djr");
                    Rel payRel = new Rel();
                    payRel.setId1(relEntityId);
                    payRel.setEntity1(entity_rel);
                    payRel.setId2(pay.getId());
                    payRel.setEntity2("CCPAY");
                    commonDao.saveDBOject(payRel, objectMapper.writeValueAsString(payRel), userId, ip);
                    
                }

            }
            String path = getPathUpload() + fnp;
            //写入文件到既定目录
            FileWrapper.createFolders(path);
            if (sbuf == null)
                sbuf = new StringBuffer(fnp);
            else
                sbuf.append(";" + fnp);
            File localFile = new File(path);
            file.transferTo(localFile);
        }
        out.println("[OK]" + sbuf.toString());
    }
 
    public void importExcel(MultipartFile files, HttpServletRequest request,
			HttpServletResponse response) {

		long start=System.currentTimeMillis(); //获取开始时间
		// 记录导入重复个数，成功个数和格式不规范个数
		int duplicateNum = 0;
		int importNum = 0;
		int unnormalNum = 0;
		
		//c4w 记下本次导入记录的起始id,用于前台显示本次导入集合		
		Long idstart = null;

		response.setContentType(CONTENT_TYPE);
		// 设置响应给前台内容的PrintWriter对象
		try {
			PrintWriter out = response.getWriter();

			InputStream is = null;
			try {
				//根据文件名判断该excel中的影像是否需要计算稿酬
				String fileName = files.getOriginalFilename();
				boolean needPayCaculate = true;
				if(fileName.contains("0稿酬"))
					needPayCaculate = false;
				
				is = files.getInputStream();
				// 根据上述创建的输入流 创建工作簿对象
				Workbook wb = WorkbookFactory.create(is);
				Sheet sheet = wb.getSheetAt(0);
				// 利用foreach循环 遍历sheet中的所有行
				// 获取顶行数据标题，以取CDLABEL和IMG_FILE列号
				int CDLABELno = -1;
				int IMG_FILEno = -1;
				Row titleRow = sheet.getRow(0);
				boolean hasTitle = true;
				// 找到CDLABEL和IMG_FILE的列号
				for (int i = 0; i < titleRow.getPhysicalNumberOfCells(); i++) {
					if (titleRow.getCell(i).toString()
							.equalsIgnoreCase("CDLABEL")) {
						CDLABELno = i;
					}
					if (titleRow.getCell(i).toString()
							.equalsIgnoreCase("IMG_FILE")) {
						IMG_FILEno = i;
					}
				}
				if (CDLABELno == -1 || IMG_FILEno == -1) {
					/*out.println("excel格式不规范，必须包含CDLABEL和IMG_FILE列");
					return;*/
					CDLABELno = 2;
					IMG_FILEno = 3;
					hasTitle = false;
				}

				String userId = commonUtil.getCurrentUserID();
				String ip = commonUtil.getIpAddress(request);

				// long time1=System.currentTimeMillis();
				// List<Image> images = searchDao.listImages();

				// 如果imageSet为空，则从数据库读入数据初始化imageSet
				long time1=System.currentTimeMillis();
				synchronized(imageSet){
					if (imageSet.isEmpty()) {
						List<Object[]> imagesInfo = searchDao.listImagesInfo();
						for (Object[] info : imagesInfo) {
							String cdlabel = (String) info[0];
							String imgFile = (String) info[1];
							// 忽略外部导入影像
							if (cdlabel == null || imgFile == null
									|| cdlabel.startsWith("Y")) {
								continue;
							}
							String infoStr = cdlabel.trim() + imgFile.trim().toLowerCase();
							imageSet.add(infoStr);
						}
					}
				}

				
				long time2=System.currentTimeMillis();
				System.out.println("检索图像耗时"+(time2-time1)+"ms");
				 

				// 遍历数据行
				for (int i = hasTitle?1:0; i <= sheet.getLastRowNum(); i++) {
					// System.out.println(".........processing line"+i);

					Row currentRow = sheet.getRow(i);
					// 根据CDLABEL和IMG_FILE列查重
					// excel中CDLABEL或IMG_FILE不为空时判重
					// long time3=System.currentTimeMillis();

					// CDLABEL或IMG_FILE为空，数据不规范
					if (currentRow.getCell(CDLABELno) == null
							|| currentRow.getCell(IMG_FILEno) == null) {
						unnormalNum++;
						continue;
					} else {
						String cdlabel = currentRow.getCell(CDLABELno)
								.toString().trim();
						String img_file = currentRow.getCell(IMG_FILEno)
								.toString().trim().toLowerCase();
						// 判断是否与数据库中有重复
						String info = cdlabel + img_file;

						// 不重复则添加至数据库并更新imageSet
						synchronized (imageSet) {
							if (!imageSet.contains(info)) {
								Image image = new Image();
								//忽略excel文件中的image_id字段，确保导入影像id>100w
/*
								String id = currentRow.getCell(1).toString();
								if (id != null) {
									double imgId = Double.parseDouble(id);
									long imageId = (long) imgId;
									image.setImageId(imageId);
								}
								
								//旧版excel格式
								/*image.setClassname(currentRow.getCell(2) == null ? null
										: currentRow.getCell(2).toString());
								image.setCdlabel(currentRow.getCell(CDLABELno) == null ? null
										: currentRow.getCell(CDLABELno)
												.toString());
								image.setImgFile(currentRow.getCell(IMG_FILEno) == null ? null
										: currentRow.getCell(IMG_FILEno)
												.toString());
								image.setObjNo(currentRow.getCell(5) == null ? null
										: currentRow.getCell(5).toString());
								image.setObjName(currentRow.getCell(6) == null ? null
										: currentRow.getCell(6).toString());
								image.setImageName(currentRow.getCell(7) == null ? null
										: currentRow.getCell(7).toString());*/
								//新版excel格式
								image.setObjNo(currentRow.getCell(0) == null ? null
										: currentRow.getCell(0).toString());
								image.setImageName(currentRow.getCell(1) == null ? null
										: currentRow.getCell(1).toString());
								image.setCdlabel(currentRow.getCell(CDLABELno) == null ? null
										: currentRow.getCell(CDLABELno)
												.toString());
								image.setImgFile(currentRow.getCell(IMG_FILEno) == null ? null
										: currentRow.getCell(IMG_FILEno)
												.toString());
								image.setPhotographer(currentRow.getCell(4) == null ? null
										: currentRow.getCell(4).toString());
								image.setHandleTime(currentRow.getCell(5) == null ? null
										: DateUtil.toDate(currentRow.getCell(5).toString(), DateUtil.DATE_FORMAT));
								
								image.setUsage("集体");
								// 导入影像同时更新稿酬表
								importImageAndPay(image, userId, ip, needPayCaculate);
								//c4w 
								if(idstart==null){
									idstart=image.getImageId();
								}
								importNum++;
								imageSet.add(info);
							} else {
								duplicateNum++;
							}
						}

					}
				}

				
				long end=System.currentTimeMillis();
				System.out.println("总耗时"+(end-start)+"ms");
				 
				out.print("excelImport");
				out.println("导入完成，成功的记录：" + importNum + "，重复的记录："
						+ duplicateNum +"，不规范的记录："+unnormalNum);
				//c4w
				if(idstart!=null){
					out.println("，起始序号："+idstart);
				}

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InvalidFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				is.close();
				out.close();
			}

		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

	}
    
    
    
    /**
     * 修改影像表和稿酬表，事务处理
     * @param image 影像
     * @param userId log日志记录的操作用户id
     * @param ip log日志记录的操作用户ip
     */
    @Transactional(readOnly = false)
	public void importImageAndPay(Image image, String userId, String ip, boolean payCaculate) {
		ObjectMapper objectMapper = new ObjectMapper();
		// 添加影像
		try {
			commonDao.saveDBOject(image,
					objectMapper.writeValueAsString(image), userId, ip);
			if(payCaculate){
				// 计算稿酬，添加至CCPay表
				CcPay pay = new CcPay();
				// //暂时将作者设为固定值资料信息中心
				pay.setAuthorId("资料信息部");
				pay.setClass_("dao.hb.Image");
				pay.setKeyval(image.getPrimaryId());
				//稿费从配置文件中读取
				pay.setReward(new BigDecimal(imageReward));
				pay.setCreated(new Date());
				pay.setTitle(image.getImageName());
	
				// 添加稿酬
				/*commonDao.saveDBOject(pay, objectMapper.writeValueAsString(pay),
						userId, ip);*/
				commonDao.savePay(image, pay, userId, ip);
			}
		} catch (JsonGenerationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonMappingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}